#pragma once
#include"buffer.hpp"
#include"message.hpp"
#include<arpa/inet.h>
#include<typeinfo>

class BaseProtocol
{
public:
    using ptr = std::shared_ptr<BaseProtocol>;
    BaseProtocol() {}
    virtual ~BaseProtocol() {}

    // 判断当前缓冲区的数据量是否支持处理
    virtual bool canProcessed(BaseBuffer::ptr buffer) = 0;
    // 从缓冲区获取一条消息
    virtual BaseMessage::ptr getOneMessage(BaseBuffer::ptr buffer) = 0;
    // 序列化
    virtual std::string serialize(BaseMessage::ptr msg) = 0;
};

class LvProtocol : public BaseProtocol
{
public:
    using ptr = std::shared_ptr<LvProtocol>;
    LvProtocol() {}
    virtual ~LvProtocol() {}

    virtual bool canProcessed(BaseBuffer::ptr buffer) override
    {
        if (buffer)
        {
            // 头4个字节表示长度
            if (buffer->readableBytes() < 4)
            {
                return false;
            }
            int32_t len = buffer->peekInt32();
            if (buffer->readableBytes() - 4 < len)
            {
                return false;
            }
            return true;
        }
        return false;
    }

    virtual BaseMessage::ptr getOneMessage(BaseBuffer::ptr buffer) override
    {
        // 头4字节：消息体的有效长度
        int32_t total_len = buffer->readInt32();
        LOG_DEBUG << "total_len = " << total_len;
        // 消息类型
        int32_t mtype = buffer->readInt32();
        auto msg = MessageTypes[(MSG_Type)mtype]->clone();
        // 创建返回消息
        // id长度
        int32_t id_len = buffer->readInt32();
        std::string id = buffer->retrieveAsString(id_len);
        LOG_DEBUG << "id = " << id;
        //body
        std::string body = buffer->retrieveAsString(total_len - 4 * 2 - id_len);
        LOG_DEBUG << "json_body = " << body;

        // 把拆解的数据设置到msg中
        msg->setType(static_cast<MSG_Type>(mtype));
        msg->setId(id);
        std::string err;
        if (!msg->unserialize(body, err))
        {
            LOG_FATAL << "把从缓冲区拿出来的数据反序列化到body失败";
            return BaseMessage::ptr(nullptr);
        }
        else
        {
            if (!msg->check())
            {
                LOG_FATAL << "消息体字段校验失败";
                return BaseMessage::ptr(nullptr);
            }
        }

        return msg;
    }

    virtual std::string serialize(BaseMessage::ptr msg) override
    {
        if (!msg)
        {
            LOG_ERROR << "serialize failed: msg is nullptr!";
            return std::string();
        }

        std::string str;
        int32_t mtype = htonl(static_cast<int32_t>(msg->getType()));
        std::string id = msg->getId();
        int32_t id_len = htonl((uint32_t)id.size());
        std:: string body;
        if (!msg->serialize(body))
        {
            LOG_ERROR << "序列化Jsob_body失败!";
            return std::string();
        }

        int32_t total_len = htonl(sizeof(mtype) + sizeof(id_len) + id.length() + body.size());

        // 组装成一条网络消息串
        str.append((char*)&total_len, 4);
        str.append((char*)&mtype, 4);
        str.append((char*)&id_len, 4);
        str.append(id);
        str.append(body);
        LOG_DEBUG << "消息序列化组装完成, 如下：";
        LOG_DEBUG << str;
        return str;
    }
};

class ProtocolFactory
{
public:
    template<typename T, typename ...Args>
    static BaseProtocol::ptr create(Args&& ...args)
    {
        return std::make_shared<T>(std::forward<Args>(args)...);
    }
};